package interpreter;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.util.ArrayList;

public class InterpreterMain {
	// SKIP a reading in the beginning & a reading in the end
	// For example if Config.interpreter_step == 30 * 1000 &
	//    & if the SKIP_MARGINS = 2 ====> skipping 1 minute at the beginning
	//										& 1 minute at the end
	//										to remove warmup & cooldown
	public static int SKIP_MARGINS = 1;
	
	public static void main(String []args) {
		if(args.length < 1) {
			System.out.println("Please use arguments:");
			System.out.println("<arg1>: folder with .raw experiment files");
			
			return ;
		}
		
		new InterpreterMain(args);
	}

	private ArrayList<RealResult> realResults;
	private String gnuplotScriptSingleExperiment = "";
	private String gnuplotScriptOneParameterVariation = "";
	private String gnuplotScriptTwoParameterVariation = "";
	
	public void InterpretFolder(String folder) {
		// Go trough all the .raw files
		File dir = new File(folder);
	    
	    FilenameFilter filter = new FilenameFilter() {
	        public boolean accept(File dir, String name) {
	            return name.endsWith(".raw");
	        }
	    };
	    String []children = dir.list(filter);
	    //String []folder_parts = folder.split("_");
	    //int MM = Integer.parseInt(folder_parts[0].substring(0, folder_parts[0].length()-1));
	    //int SS = Integer.parseInt(folder_parts[1].substring(0, folder_parts[1].length()-1));
	    //int CC = Integer.parseInt(folder_parts[2].substring(0, folder_parts[1].length()-1));
	    
	    this.gnuplotScriptSingleExperiment = "";
	    if (children == null) {
	        // Either dir does not exist or is not a directory
	    } else {
	        for (int i=0; i<children.length; i++) {
	            // Get filename of file or directory
	            String filename = children[i];
	            String in = filename;
	            String out = filename.replaceAll("\\.raw", ".txt");
	            
	            String inpath = folder + (folder.endsWith("/") ? in : "/" + in);
	            String outpath = folder + (folder.endsWith("/") ? out : "/" + out);
	            
	            String []parts = (filename.replaceAll("\\.raw", "")).split("_");
	            int MM = Integer.parseInt(parts[0].substring(2));
	            int SS = Integer.parseInt(parts[1].substring(2));
	            int FF = Integer.parseInt(parts[2].substring(1));
	            if(parts[2].substring(1).equals("01")) {
	            	//System.out.println("FOR FILE " + in + ", scaling factor will be 10");
	            	FF = 10;
	            } else if (parts[2].substring(1).equals("001")) {
	            	//System.out.println("FOR FILE " + in + ", scaling factor will be 1");
	            	FF = 1;
	            }
	            //int FF = Integer.parseInt(parts[2].substring(2));
	            int C = Integer.parseInt(parts[3].substring(1));
	            int P = Integer.parseInt(parts[4].substring(1));
	            int L = Integer.parseInt(parts[5].substring(1));
	            int M = Integer.parseInt(parts[6].substring(1));
	            
	            if ( M % P !=0 ) {
	            	System.err.println("Bad experiment file, M % P != 0 for " + filename);
	            	return;
	            }
	            
	            if ( P != SS) {
	            	System.err.println("Bad experiment file, P != SS for " + filename);
	            	return;
	            }
	            
	            M = M / P;
	            M = M * MM;
	            P = 1;
	            
	            int []params = new int[] { 
	            		MM, 
	            		SS,
	            		FF,
	            		C, 
//	            		P, 
//	            		L, 
	            		M 
	            }; 
	            
	            RealResult r = SingleExperimentInterpreter.DoFile(params,inpath,outpath);
	            realResults.add(r);
	            //System.err.println("Experiment: MM:"+MM+", SS:"+SS+", FF:"+FF+", C:"+C+", M:"+M);
	            System.out.println();
	            System.out.println();
	            System.out.println();
	            System.out.println();
	            this.gnuplotScriptSingleExperiment += SingleExperimentInterpreter.getGnuPlotForExperiment(out, params);
	        }
	    }
	    
	    String outFilename;
	    
	    outFilename = folder + (folder.endsWith("/") ? "single.p" : "/single.p");
	    writeStringToFile(outFilename, this.gnuplotScriptSingleExperiment);
	}
	
	public InterpreterMain(String[] folders) {
		
		realResults = new ArrayList<RealResult>();
		
	    RealResult.params_codes = new String [] { 
	    	"MM",
	    	"SS",
	    	"FF",
	    	"C",
//	    	"P",
//	    	"L",
	    	"M" };
	    RealResult.params_names = new String [] {
    		"Number of Middle Men",
			"Number of Servers",
			"Scaling factor",
			"Number of Clients",
//			"Number of Queues",
//			"Size of Queues",
			"Number of Worker Threads" };

	    for(String folder : folders) {
			InterpretFolder(folder);
		}
		
	    System.err.println("Collecting data from " + realResults.size() + " experiments.");
	    
	    String outFilename;
	    
	    for(RealResult r : realResults) {
	    	// Try to make some params variable
	    	int []params;
	    	for(int i=0; i<r.params.length; i++) {
	    		params = r.params.clone();
	    		params[i] = 0;
	    		gnuplotScriptOneParameterVariation += OneParameterVariation.doFilesAndPlot("gnuplot", i, params, realResults);
	    	}
	    	for(int i=0; i<r.params.length; i++) {
	    		for(int j=0; j<r.params.length; j++) {
	    			params = r.params.clone();
	    			params[i] = 0;
	    			params[j] = 0;
	    			gnuplotScriptTwoParameterVariation += TwoParameterVariation.plotVeryInterestingResults("gnuplot", params, i, j, realResults);
	    		}
	    	}
	    }
	    
	    outFilename = "gnuplot/one.p";
	    writeStringToFile(outFilename, this.gnuplotScriptOneParameterVariation);

	    outFilename = "gnuplot/two.p";
	    writeStringToFile(outFilename, this.gnuplotScriptTwoParameterVariation);

	    solveTask1(realResults);
	}
	
	private static void writeStringToFile(String filename, String contents) {
		try {
	    	FileWriter fstream = new FileWriter(filename, false);
			BufferedWriter outFile = new BufferedWriter(fstream);
			outFile.write(contents);
			outFile.close();
		} catch (Exception e) {
			System.out.println("Can't write to "+filename+"!!!");
			e.printStackTrace();
		}
	}
	
	;
	private void solveTask1(ArrayList<RealResult> results) {
		System.out.println("Hi there, I am here solving Task 1");
		if(results.size() != 8) {
			System.out.println("Are you sure you are solving Task1?");
			System.out.println("I'm just saying this because I was expecting 8 experiments...");
			System.out.println("So try again later when you have 8 experiments");
			return;
		}
		
		// Throughput 
		double [][][][] T_y = new double[2][2][2][10];
		// Think Time
		double [][][][] TT_y = new double[2][2][2][10];
		// Response Time
		double [][][][] RT_y = new double[2][2][2][10];
		
		for(int i=0; i<2; i++) {
			for(int j=0; j<2; j++) {
				for(int k=0; k<2; k++) {
					if(fill_y(T_y, results, i,j,k, i+1,j+1,9*k+1, 10, "Throughput") == false) {
						return;
					}
					if(fill_y(TT_y, results, i,j,k, i+1,j+1,9*k+1, 10, "Think Time") == false) {
						return;
					}
					if(fill_y(RT_y, results, i,j,k, i+1,j+1,9*k+1, 10, "Response Time") == false) {
						return;
					}
				}
			}
		}
		System.out.println();
		System.out.println();
		System.out.println("-------------------------------");
		System.out.println("Throughput");
		Task1Solver ThroughputSolver = new Task1Solver();
		ThroughputSolver.solve(T_y);
		
		System.out.println();
		System.out.println();
		System.out.println("-------------------------------");
		System.out.println("ThinkTime");
		Task1Solver ThinkTimeSolver = new Task1Solver();
		ThinkTimeSolver.solve(TT_y);
		
		System.out.println();
		System.out.println();
		System.out.println("-------------------------------");
		System.out.println("ResponseTime");
		Task1Solver ResponseTimeSolver = new Task1Solver();
		ResponseTimeSolver.solve(RT_y);
		
		
		//System.out.println("y filled in :)");
	}
	
	private boolean fill_y(double [][][][]y, ArrayList<RealResult> results, int i, int j, int k, int SS, int MM, int FF, int R, String fillWithWhat) {
		
		RealResult t = locateSpecificMeasurement(results, SS, MM, FF);
		if(t==null) return false;
		if(t.steps < R) {
			System.out.println("Are you sure you are solving Task1?");
			System.out.println("I'm just saying because you don't have at least 10 measurements for "+SS+" servers, "+MM+" middle men and "+(((double)FF/100))+" scaling factor");
			return false;
		}
		for(int l=0; l<R; l++) {
			if(fillWithWhat.equals("Throughput")) {
				y[i][j][k][l] = t.measuredThroughput[l];
			} else if(fillWithWhat.equals("Think Time")) {
				y[i][j][k][l] = t.measuredThinkTime[l];
			} else if(fillWithWhat.equals("Response Time")) {
				y[i][j][k][l] = t.measuredResponseTime[l];
			} else {
				return false;
			}
		}
		return true;
	}
	
	private RealResult locateSpecificMeasurement(ArrayList<RealResult> results, int SS, int MM, int FF) {
		int SS_index = 1;
		int MM_index = 0;
		int FF_index = 2;
		for(RealResult r : results) {
			if(r.params[SS_index] == SS && r.params[MM_index] == MM && r.params[FF_index] == FF) {
				return r;
			}
		}
		System.out.println("Are you sure you are solving Task1?");
		System.out.println("I'm just saying because I could not find the test for "+SS+" servers, "+MM+" middle men and "+(((double)FF/100))+" scaling factor" );
		return null;
	}
}
